package com.fa.service;

import com.fa.utils.CameStringUtils;
import com.fa.utils.FieldTypeMapper;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static com.fa.utils.CameStringUtils.toCamelCaseClassName;

@Service
public class CodeGeneratorService {

    // Java 类型到导入包的映射
    private static final Map<String, String> javaTypeToImport = new HashMap<>();

    static {
        javaTypeToImport.put("LocalDate", "java.time.LocalDate");
        javaTypeToImport.put("LocalTime", "java.time.LocalTime");
        javaTypeToImport.put("LocalDateTime", "java.time.LocalDateTime");
        javaTypeToImport.put("BigDecimal", "java.math.BigDecimal");
//        javaTypeToImport.put("Boolean", "java.lang.Boolean");
//        javaTypeToImport.put("Integer", "java.lang.Integer");
//        javaTypeToImport.put("Long", "java.lang.Long");
//        javaTypeToImport.put("Float", "java.lang.Float");
//        javaTypeToImport.put("Double", "java.lang.Double");
//        javaTypeToImport.put("Byte", "java.lang.Byte");
//        javaTypeToImport.put("Short", "java.lang.Short");
        // 根据需要添加更多的类型映射
    }

    private final VelocityEngine velocityEngine;
    @Autowired
    private DatabaseMetadataService databaseMetadataService;

    public CodeGeneratorService() {
        Properties properties = new Properties();
        properties.setProperty("resource.loader", "file");
        properties.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.FileResourceLoader");
        properties.setProperty("file.resource.loader.path", "src/main/resources/templates");
        velocityEngine = new VelocityEngine(properties);
        velocityEngine.init();
    }

    /**
     * 生成代码并通过 ZipOutputStream 压缩输出
     *
     * @param databaseName    数据库名称
     * @param tableName       表名
     * @param zipOutputStream ZIP 输出流
     * @throws Exception
     */
    public void generateCodeToZipStream(String databaseName, String tableName, ZipOutputStream zipOutputStream) throws Exception {
        List<Map<String, String>> fields = databaseMetadataService.getTableMetadata(databaseName, tableName);

        // 将类名转换为驼峰格式，首字母大写
        String className = toCamelCaseClassName(tableName);
        // 生成 Entity 文件
        generateEntity(className, tableName, fields, zipOutputStream);
        // 生成 Mapper 文件
        generateMapper(className, zipOutputStream);
        // 生成 Service 文件
        generateService(className, zipOutputStream);
        // 生成 ServiceImpl 文件
        generateServiceImpl(className, zipOutputStream);
        // 生成 Controller 文件
        generateController(className, zipOutputStream);
    }


    private void generateEntity(String className, String tableName, List<Map<String, String>> fields, ZipOutputStream zipOutputStream) throws IOException {
        Template template = velocityEngine.getTemplate("entity.java.vm");
        // 构建字段数据，映射数据库类型到 Java 类型，并收集导入的包
        Set<String> imports = new HashSet<>();
        // 构建字段数据，映射数据库类型到 Java 类型
        fields.forEach(field -> {
            String dbType = field.get("type");  // 假设数据库类型在元数据中存储为 "type" 字段
            String javaType = FieldTypeMapper.mapToJavaType(dbType);
            field.put("javaType", javaType);  // 将映射后的 Java 类型存入字段数据
            // 获取数据库字段名，并将其转换为驼峰命名
            String dbFieldName = field.get("name");
            String camelFieldName = CameStringUtils.toCamelCase(dbFieldName);
            field.put("camelFieldName", camelFieldName);
            // 根据 Java 类型查找并添加需要导入的包
            if (javaTypeToImport.containsKey(javaType)) {
                imports.add(javaTypeToImport.get(javaType));
            }
        });

        VelocityContext context = new VelocityContext();
        context.put("packageName", "com.fa");
        context.put("className", className);
        context.put("fields", fields);
        context.put("imports", imports);
        context.put("tableName", tableName);

        // 生成代码并写入 ZipOutputStream
        StringWriter stringWriter = new StringWriter();
        template.merge(context, stringWriter);
        addToZip(className + ".java", stringWriter.toString(), zipOutputStream);
    }

    private void generateMapper(String className, ZipOutputStream zipOutputStream) throws IOException {
        Template template = velocityEngine.getTemplate("mapper.java.vm");

        VelocityContext context = new VelocityContext();
        context.put("packageName", "com.fa");
        context.put("className", className);

        StringWriter stringWriter = new StringWriter();
        template.merge(context, stringWriter);
        addToZip(className + "Mapper.java", stringWriter.toString(), zipOutputStream);
    }

    private void generateService(String className, ZipOutputStream zipOutputStream) throws IOException {
        Template template = velocityEngine.getTemplate("service.java.vm");

        VelocityContext context = new VelocityContext();
        context.put("packageName", "com.fa");
        context.put("className", className);

        StringWriter stringWriter = new StringWriter();
        template.merge(context, stringWriter);
        addToZip(className + "Service.java", stringWriter.toString(), zipOutputStream);
    }

    private void generateServiceImpl(String className, ZipOutputStream zipOutputStream) throws IOException {
        Template template = velocityEngine.getTemplate("ServiceImpl.java.vm");

        VelocityContext context = new VelocityContext();
        context.put("packageName", "com.fa");
        context.put("className", className);

        StringWriter stringWriter = new StringWriter();
        template.merge(context, stringWriter);
        addToZip(className + "ServiceImpl.java", stringWriter.toString(), zipOutputStream);
    }

    private void generateController(String className, ZipOutputStream zipOutputStream) throws IOException {
        Template template = velocityEngine.getTemplate("controller.java.vm");

        VelocityContext context = new VelocityContext();
        context.put("packageName", "com.example.controller");
        context.put("className", className);

        StringWriter stringWriter = new StringWriter();
        template.merge(context, stringWriter);
        addToZip(className + "Controller.java", stringWriter.toString(), zipOutputStream);
    }

    /**
     * 将生成的代码内容添加到 ZIP 文件中
     *
     * @param fileName        文件名
     * @param fileContent     文件内容
     * @param zipOutputStream ZIP 输出流
     * @throws IOException
     */
    private void addToZip(String fileName, String fileContent, ZipOutputStream zipOutputStream) throws IOException {
        zipOutputStream.putNextEntry(new ZipEntry(fileName));
        zipOutputStream.write(fileContent.getBytes());
        zipOutputStream.closeEntry();
    }
}
